package top.sxlai.service.impl;

import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.springframework.beans.factory.annotation.Autowired;
import top.sxlai.constant.OtherStatus;
import top.sxlai.entity.DTO.FileFolderDTO;
import top.sxlai.entity.OpFile;
import top.sxlai.entity.OpFolder;
import top.sxlai.entity.aggregation.AggregationFileFolder;
import top.sxlai.service.IFileFolderService;
import top.sxlai.util.CurrentSystemTime;
import top.sxlai.util.hbase.HbaseDML;
import top.sxlai.util.hbase.ParameterInitializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : sxl
 * @date : 2024/4/16 21:41
 * @Version: 1.0
 */
@Service
@Slf4j
public class FileFolderServiceImpl implements IFileFolderService {
    //    @Autowired
//    private IFileService iFileService;
//    @Autowired
//    private IFolderService iFolderService;
    @Value("${hadoop.hdfsUrl}")
    private String hdfsUrl;
    @Value("${hbaseData.namespace}")
    private String namespace;
    @Value("${hbaseData.tables.folderTableName.tableName}")
    private String folderTableName;
    @Value("${hbaseData.tables.folderTableName.columnFamily}")
    private String folderColumnFamily;
    @Value("${hbaseData.tables.fileTableName.tableName}")
    private String fileTableName;
    @Value("${hbaseData.tables.fileTableName.columnFamily}")
    private String fileColumnFamily;
    @Autowired
    private FileSystem fileSystem;

    /**
     * 删除文件
     *
     * @param aggregationFileFolder 聚合数据
     * @return ResponseEntity
     */
    @Override
    public ResponseEntity<Map<String, String>> deleteFiles(AggregationFileFolder aggregationFileFolder) throws IOException {
        Map<String, String> response = new HashMap<>();
        //删除文件
        if (aggregationFileFolder.getOpFiles() != null) {
            log.info("开始删除文件,时间:{}", CurrentSystemTime.getTime());
            for (OpFile opFile : aggregationFileFolder.getOpFiles()) {
                Path path = new Path(opFile.getHdfsPath());
                //删除hdfs上的数据
                boolean success = fileSystem.delete(path, true);
                if (success) {
                    //删除hbase的数据
                    HbaseDML.deleteColumns(namespace, fileTableName, opFile.getHdfsPath(), fileColumnFamily, ParameterInitializer.getFileColumns());
                    //在这里执行空间大小的计算
                } else {
                    response.put("message", OtherStatus.DELETEFILEFAILURE.getMessage() + " 名称: " + opFile.getFileName());
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                }
            }
        }

        Path path;
        //删除文件夹的时候要将文件夹里面的全部文件都删除
        if (aggregationFileFolder.getOpFolders() != null) {
            log.info("开始删除文件夹,时间:{}", CurrentSystemTime.getTime());
            for (OpFolder opFolder : aggregationFileFolder.getOpFolders()) {
                path = new Path(opFolder.getHdfsPath());
                //删除hdfs上的数据
                boolean success = fileSystem.delete(path, true);
                if (success) {
                    //删除hbase的数据
                    HbaseDML.deleteColumns(namespace, folderTableName, opFolder.getHdfsPath(), folderColumnFamily, ParameterInitializer.getFolderColumns());
                    //删除folder里的全部文件
                    //查询全部文件的键
                    List<String> opFilesKeys = HbaseDML.getAllKeys(namespace, fileTableName, opFolder.getHdfsPath());
                    if (!opFilesKeys.isEmpty()) {
                        for (String opFilePath : opFilesKeys) {
                            path = new Path(opFilePath);
                            //删除hdfs上的数据
                            boolean success1 = fileSystem.delete(path, true);
                            if (success1) {
                                //删除hbase的数据
                                HbaseDML.deleteColumns(namespace, fileTableName, opFilePath, fileColumnFamily, ParameterInitializer.getFileColumns());
                                //在这里执行空间大小的计算
                            } else {
                                log.info("删除子文件夹失败,时间:{}", CurrentSystemTime.getTime());
                                response.put("message", OtherStatus.DELETEFOLDERFAILURE.getMessage() + " 名称: " + opFolder.getFolderName());
                                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                            }
                        }
                    }
                    //查询全部的子级文件夹的键
                    List<String> opFolderKeys = HbaseDML.getAllKeys(namespace, folderTableName, opFolder.getHdfsPath());
                    if (!opFilesKeys.isEmpty()) {
                        for (String opFolderKey : opFolderKeys) {
                            path = new Path(opFolderKey);
                            //删除hdfs上的数据
                            boolean success2 = fileSystem.delete(path, true);
                            if (success2) {
                                //删除hbase的数据
                                HbaseDML.deleteColumns(namespace, folderTableName, opFolderKey, folderColumnFamily, ParameterInitializer.getFolderColumns());
                                //在这里执行空间大小的计算
                            } else {
                                log.info("删除文件夹里的文件失败,时间:{}", CurrentSystemTime.getTime());
                                response.put("message", OtherStatus.DELETEFOLDERFAILURE.getMessage() + " 名称: " + opFolder.getFolderName());
                                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                            }
                        }
                    }
                } else {
                    log.info("删除文件夹失败,时间:{}", CurrentSystemTime.getTime());
                    response.put("message", OtherStatus.DELETEFOLDERFAILURE.getMessage() + " 名称: " + opFolder.getFolderName());
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                }
            }
            //删除文件夹,要将文件夹里面的全部文件都删除
            aggregationFileFolder.getOpFolders().forEach(item -> {
                try {
                    HbaseDML.deleteColumns(namespace, folderTableName, item.getHdfsPath(), folderColumnFamily, ParameterInitializer.getFolderColumns());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
//
        response.put("message", OtherStatus.DELETEBOTHSUCCESS.getMessage());
        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

    /**
     * 回收文件到回收站
     *
     * @param aggregationFileFolder 聚合数据
     * @return ResponseEntity
     */
    @Override
    public ResponseEntity<Map<String, String>> recycleFiles(AggregationFileFolder aggregationFileFolder) {
        //回收状态为0
        String recycleValue = "0";
        //复原状态为1
        String restoreValue = "1";
        //线判断是回收还是复原
        if ("recycle".equals(aggregationFileFolder.getDeleteWay())) {
            return updateStatus(aggregationFileFolder, recycleValue);
        } else if ("restore".equals(aggregationFileFolder.getDeleteWay())) {
            return updateStatus(aggregationFileFolder, restoreValue);
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }

    /**
     * 移动文件路径
     *
     * @param aggregationFileFolder 聚合数据
     * @return ResponseEntity
     */
    @Override
    public ResponseEntity<Map<String, String>> moveFilePath(AggregationFileFolder aggregationFileFolder) throws IOException {
        boolean isMove1 = false;
        boolean isMove2 = false;
        Map<String, String> response = new HashMap<>();
        //先移动文件路径
        if (aggregationFileFolder.getOpFiles() != null) {
            log.info("开始移动文件路径,时间:{}", CurrentSystemTime.getTime());
            for (OpFile opFile : aggregationFileFolder.getOpFiles()) {
                try {
                    String newFilePath = getNewFilePath3(opFile.getHdfsPath(), aggregationFileFolder.getMovePath());
                    isMove1 = HbaseDML.updateFileRowKey(namespace, fileTableName, opFile.getHdfsPath(), fileColumnFamily, newFilePath);
                    if (isMove1) {
                        //移动hdfs上的路径
                        moveHdfsPath(opFile.getHdfsPath(), newFilePath);
                        //修改存储在hbase的hdfs上的路径
                        HbaseDML.updateColumn(namespace, fileTableName,newFilePath , fileColumnFamily, "hdfsPath", newFilePath);
                    } else {
                        log.info("移动文件路径失败,时间:{}", CurrentSystemTime.getTime());
                        response.put("message", OtherStatus.MOVEFILEFAILURE.getMessage() + " 名称: " + opFile.getFileName());
                        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        //移动文件夹的时候要将文件夹里面的全部文件都移动
        if (aggregationFileFolder.getOpFolders() != null) {
            log.info("开始移动文件夹路径,时间:{}", CurrentSystemTime.getTime());
            //移动文件夹
            for (OpFolder folder : aggregationFileFolder.getOpFolders()) {
                isMove2 = HbaseDML.updateFileRowKey(namespace, folderTableName, folder.getHdfsPath(), folderColumnFamily, getNewFolderPath(folder.getHdfsPath(), aggregationFileFolder.getMovePath()));
                if (isMove2) {
                    //移动文件夹
                    moveHdfsPath(folder.getHdfsPath(), getNewFolderPath(folder.getHdfsPath(), aggregationFileFolder.getMovePath()));
                    HbaseDML.updateColumn(namespace, folderTableName, getNewFolderPath(folder.getHdfsPath(), aggregationFileFolder.getMovePath()), folderColumnFamily, "hdfsPath", getNewFolderPath(folder.getHdfsPath(), aggregationFileFolder.getMovePath()));
                    //获取旧文件夹下的所有文件的行键
                    List<String> opFiles = HbaseDML.getAllKeys(namespace, fileTableName, folder.getHdfsPath());
                    //移动旧文件夹下的所有文件
                    for (String opFilePath : opFiles) {
                        try {
                            isMove2 = HbaseDML.updateFileRowKey(namespace, fileTableName, opFilePath, fileColumnFamily, getNewFilePath2(opFilePath, aggregationFileFolder.getMovePath(), folder.getHdfsPath()));
                            if (isMove2) {
                                //移动hdfs上的路径
                                moveHdfsPath(opFilePath, getNewFilePath2(opFilePath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()));
                                //修改hbase上的hdfs路径
                                HbaseDML.updateColumn(namespace, fileTableName, getNewFilePath2(opFilePath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()), fileColumnFamily, "hdfsPath", getNewFilePath2(opFilePath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()));
                            } else {
                                log.info("移动旧文件夹下文件路径失败,时间:{}", CurrentSystemTime.getTime());
                                response.put("message", "文件夹下" + OtherStatus.MOVEFILEFAILURE.getMessage() + ", 文件名称: " + opFilePath);
                                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    //获取旧文件下的所有子文件夹
                    List<String> opFolders = HbaseDML.getAllKeys(namespace, folderTableName, folder.getHdfsPath());
                    // 移动旧文件夹下的所有子文件夹
                    for (String oldFolderPath : opFolders) {
                        try {
                            isMove2 = HbaseDML.updateFileRowKey(namespace, folderTableName, oldFolderPath, folderColumnFamily, getNewFilePath2(oldFolderPath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()));
                            if (isMove2) {
                                moveHdfsPath(oldFolderPath,  getNewFilePath2(oldFolderPath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()));
                                //移动hbase上的hdfs路径
                                HbaseDML.updateColumn(namespace, folderTableName,  getNewFilePath2(oldFolderPath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()), folderColumnFamily, "hdfsPath",  getNewFilePath2(oldFolderPath, aggregationFileFolder.getMovePath(),folder.getHdfsPath()));
                            } else {
                                log.info("移动子文件夹路径失败,时间:{}", CurrentSystemTime.getTime());
                                response.put("message", OtherStatus.MOVEFOLDERFAILURE.getMessage() + ",移动子文件夹路径失败,，文件名称: " + oldFolderPath);
                                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                } else {
                    log.info("移动文件夹路径失败,时间:{}", CurrentSystemTime.getTime());
                    response.put("message", OtherStatus.MOVEFOLDERFAILURE.getMessage() + "文件夹名称: " + folder.getFolderName());
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
                }
            }
        }

        if (isMove1 && isMove2) { //两个都移动了
            log.info("文件和文件夹移动成功,时间:{}", CurrentSystemTime.getTime());
            response.put("message", OtherStatus.MOVEBOTHSUCCCESS.getMessage());
            return ResponseEntity.ok(response);
        } else if (isMove1) { //只有文件移动
            log.info("移动文件成功,时间:{}", CurrentSystemTime.getTime());
            response.put("message", OtherStatus.MOVEFILESUCCESS.getMessage());
            return ResponseEntity.ok(response);
        } else if (isMove2) { //只有文件夹移动
            log.info("移动文件夹成功,时间:{}", CurrentSystemTime.getTime());
            response.put("message", OtherStatus.MOVEFILESUCCESS.getMessage());
            return ResponseEntity.ok(response);
        } else {//移动失败
            response.put("message", OtherStatus.MOVEBOTHFAILURE.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 重命名文件和文件夹
     *
     * @param fileFolderDTO
     * @return
     */
    @Override
    public ResponseEntity<Map<String, String>> rename(FileFolderDTO fileFolderDTO) throws IOException {
        boolean isRename1 = true;
        boolean isRename2 = true;
        Map<String, String> response = new HashMap<>();
        //如果是文件则进行文件名的修改
        if ("File".equals(fileFolderDTO.getType())) {
            //修改行键
            String newPath = getNewName(fileFolderDTO.getHdfsPath(), fileFolderDTO.getNewName());
            isRename1 = HbaseDML.updateFileRowKey(namespace, fileTableName, fileFolderDTO.getHdfsPath(), fileColumnFamily, newPath);
            if (isRename1) {
                //修改hdfs上的路径
                moveHdfsPath(fileFolderDTO.getHdfsPath(), newPath);
                //修改hbase上的hdfs路径
                HbaseDML.updateColumn(namespace, fileTableName, newPath, fileColumnFamily, "hdfsPath", newPath);
                //修改hbase上的名称
                HbaseDML.updateColumn(namespace, fileTableName, newPath, fileColumnFamily, "fileName", fileFolderDTO.getNewName());
            } else {
                log.info("重命名文件失败,时间:{}", CurrentSystemTime.getTime());
                response.put("message", OtherStatus.RENAMEFILEFAILURE.getMessage() + "文件名称: " + fileFolderDTO.getHdfsPath());
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
            }
        }
        response.put("message", OtherStatus.RENAMEFILESUCCESS.getMessage());
        return ResponseEntity.ok(response);
    }

    //获取新的文件的路径名称
    private String getNewName(String hdfsPath, String newName) {
        // 找到最后一个斜杠的位置
        int lastSlashIndex = hdfsPath.lastIndexOf("/");
        // 截取路径，去掉最后一个部分
        String newPath = hdfsPath.substring(0, lastSlashIndex + 1);
        // 拼接新的文件路径
        newPath += newName;
        return newPath;
    }

    /**
     * 移动hdfs上的路径
     *
     * @param oldHdfsPath 旧路径
     * @param newHdfsPath 新路径
     * @throws IOException 异常
     */

    private void moveHdfsPath(String oldHdfsPath, String newHdfsPath) throws IOException {
        Path oldPath = new Path(oldHdfsPath);
        Path dnewPath = new Path(newHdfsPath);
        fileSystem.rename(oldPath, dnewPath);
    }

    /**
     * 返回新的文件路径
     *
     * @param hdfsPath
     * @return
     */

    private String getNewFolderPath(String oldPath, String hdfsPath) {
        String[] parts = oldPath.split("/");
        String newFilePath = "";
        //提取最后的一个部分
        String lastPart = parts[parts.length - 1];
        //将新达到值和它拼接起来
        newFilePath = hdfsPath + "/" + lastPart;
//        if (parts.length > 1) {
//            parts[0] = hdfsPath; // 将第一个路径部分修改为新的值
//            newFilePath = String.join("/", parts);
//        }
        return newFilePath;
    }

    private String getNewFilePath(String oldPath, String hdfsPath) {
        String[] parts = oldPath.split("/");
        //如果只是两个则 返回最后一个
        if (parts.length == 2) {
            return hdfsPath + "/" + parts[parts.length - 1];
        } else {
            //否则返回最后两个并进行拼接
            String lastPart = parts[parts.length - 1];
            String lastPart2 = parts[parts.length - 2];
            return hdfsPath + "/" + lastPart2 + "/" + lastPart;
        }
    }

    private String getNewFilePath2(String oldPath, String hdfsPath,String fatherFolder) {
        String[] parts = oldPath.split("/");
        String[] partsFather = fatherFolder.split("/");
        int startIndex = partsFather.length-1;
        //直接去掉第一个然后拼接剩下的
        StringBuilder newPath = new StringBuilder();
        for (int i = startIndex; i < parts.length; i++) {
            newPath.append("/").append(parts[i]);
        }
        return hdfsPath + newPath;
    }

    private String getNewFilePath3(String oldPath, String hdfsPath) {
        String[] parts = oldPath.split("/");
        String lastPart = parts[parts.length - 1];
        return hdfsPath + "/" + lastPart;
    }

    private static String getFileExtension(String fileName) {
        if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        } else {
            return ""; // 如果文件名中没有后缀名，则返回空字符串
        }
    }

    /**
     * 更新文件状态
     *
     * @param aggregationFileFolder
     * @param recycleValue
     * @return
     */
    private ResponseEntity<Map<String, String>> updateStatus(AggregationFileFolder aggregationFileFolder, String recycleValue) {
        int isRecycle1;
        int isRecycle2;
        Map<String, String> response = new HashMap<>();
        if (aggregationFileFolder.getOpFiles() != null) {//文件不为空进行回收操作
            log.info("开始回收文件,时间:{}", CurrentSystemTime.getTime());
            isRecycle1 = 1;
            aggregationFileFolder.getOpFiles().forEach(item -> {
                try {
                    HbaseDML.updateColumn(namespace, fileTableName, item.getHdfsPath(), fileColumnFamily, "status", recycleValue);//修改为0
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        } else {
            isRecycle1 = 0;
        }
        if (aggregationFileFolder.getOpFolders() != null) {//文件夹不为空进行回收操作
            log.info("开始回收文件夹,时间:{}", CurrentSystemTime.getTime());
            isRecycle2 = 1;
            aggregationFileFolder.getOpFolders().forEach(folder -> {
                try {
                    HbaseDML.updateColumn(namespace, folderTableName, folder.getHdfsPath(), folderColumnFamily, "status", recycleValue);
                    //查询出来该文件夹下的所有子文件的键
                    List<String> opFiles = HbaseDML.getAllKeys(namespace, fileTableName, folder.getHdfsPath());
                    //修改该文件夹下的所有子文件状态
                    opFiles.forEach(item -> {
                        try {
                            HbaseDML.updateColumn(namespace, fileTableName, item, fileColumnFamily, "status", recycleValue);//修改为0
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });
                    //查询出来该文件夹下的所有子文件夹的键
                    List<String> opFolders = HbaseDML.getAllKeys(namespace, folderTableName, folder.getHdfsPath());
                    //修改该文件夹下的所有子文件夹状态
                    opFolders.forEach(item -> {
                        try {
                            HbaseDML.updateColumn(namespace, folderTableName, item, folderColumnFamily, "status", recycleValue);//修改为0
                        } catch (IOException e) {
                            throw new RuntimeException();
                        }
                    });
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        } else {
            isRecycle2 = 0;
        }
        if (isRecycle1 == 1 && isRecycle2 == 1) { //两个都回收了
            log.info("回收文件和文件夹成功,时间:{}", CurrentSystemTime.getTime());
            response.put("message", OtherStatus.RECYCLEBOTHSUCCESS.getMessage());
            return ResponseEntity.ok(response);
        } else if (isRecycle1 == 1) { //只有文件回收
            log.info("回收文件,时间:{}", CurrentSystemTime.getTime());
            response.put("message", OtherStatus.RECYCLEFILESUCCESS.getMessage());
            return ResponseEntity.ok(response);
        } else if (isRecycle2 == 1) { //只有文件夹回收
            log.info("回收文件夹成功,时间:{}", CurrentSystemTime.getTime());
            response.put("message", OtherStatus.RECYCLEFOLDERSUCCESS.getMessage());
            return ResponseEntity.ok(response);
        } else {//回收失败
            response.put("message", OtherStatus.RECYCLEBOTHFAILURE.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }
}
